package http.raw;

import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import http.HTTPException;
import http.HTTPMethod;
import http.IHTTPListener;
import http.IHttpClient;

import org.apache.http.NameValuePair;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.message.BasicNameValuePair;

import com.erp.service.util.JSONHelper;
import com.erp.service.util.net.IResponseInfo;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

public class HttpURLConnectionClient implements IHttpClient {

	/**
	 * 请求方式
	 */
	private HTTPMethod httpMethod = HTTPMethod.GET;
	
	/**
	 * 服务器的主机头地址
	 */
    private String serverUrl;
    
    /**
     * 请求访问地址
     */
    private String appendUrl = "";
    
    /**
     * 请求访问的完整地址
     */
    private Uri fullUri;
    
    /**
     * 请求头信息
     */
    private Map<String, String>  headers;

    /**
     * 请求参数
     */
    private List<NameValuePair> queryStrings;
    
	/**
	 * 请求主体内容
	 */
    private String bodyString;
    
    private Object entity;
    
    /**
     * 连接超时时长
     */
    private int connectTimeout;
    
    /**
     * 请求超时时长
     */
    private int readTimeout;
    
    

    public HttpURLConnectionClient() {
        headers= new HashMap<String, String>();
        queryStrings = new ArrayList<NameValuePair>();
    }
    
    @Override
    public IHttpClient setHttpMethod(HTTPMethod httpMethod) {
        this.httpMethod = httpMethod;
        return this;
    }

    @Override
    public IHttpClient setServerUrlPrefix(String serverUrl) {
        this.serverUrl = serverUrl;
        return this;
    }
    
    @Override
    public IHttpClient setAppendUrl(String appendUrl) {
        this.appendUrl += appendUrl;
        return this;
    }

    @Override
    public IHttpClient setFullUrl(String fullUrl) {
        this.fullUri = Uri.parse(fullUrl);
        return this;
    }
    
    @Override
    public IHttpClient setFullUrl(Uri fullUri) {
        this.fullUri = fullUri;
        return this;
    }
    
    @Override
    public IHttpClient setHeaders(Map<String, String> headers) {
        this.headers.putAll(headers);
        return this;
    }

    @Override
    public IHttpClient setHeader(String name, String value) {
        this.headers.put(name, value);
        return this;
    }

    @Override
    public IHttpClient setQueryStrings(Map<String, String> queryStrings) {
        for (String key : queryStrings.keySet())
            this.queryStrings.add(new BasicNameValuePair(key, queryStrings.get(key)));
        return this;
    }
    
    @Override
    public IHttpClient setQueryStrings(List<NameValuePair> queryStrings) {
        this.queryStrings.addAll(queryStrings);
        return this;
    }
    
    @Override
    public IHttpClient setQueryString(String name, String value) {
        this.queryStrings.add(new BasicNameValuePair(name, value));
        return this;
    }
    
    @Override
    public IHttpClient setBodyString(String bodyString) {
        this.bodyString = bodyString;
        return this;
    }
    
    @Override
    public IHttpClient setJsonBody(Object entity) {
        this.entity = entity;
        return this;
    }

    @Override
    public IHttpClient setReadTimeout(int timeout) {
        this.readTimeout = timeout;
        return this;
    }    

    @Override
    public IHttpClient setConnectTimeout(int timeout) {
        this.connectTimeout = timeout;
        return this;
    }
    
    /**
     * 获取请求方式
     * @return
     */
    protected String getMethod() {
        if (httpMethod.equals(HTTPMethod.POST))
            return "POST";
        return "GET";
    }
    
    /**
     * 获取完整的URI地址
     * @return
     */
    protected Uri getUri() {
        if (fullUri == null) {
        	if (!TextUtils.isEmpty(serverUrl) && !TextUtils.isEmpty(appendUrl) && !serverUrl.substring(serverUrl.length()-1).equals("/"))
        		serverUrl += "/";
        	
        	if (!TextUtils.isEmpty(appendUrl) && appendUrl.substring(0, 1).equals("/"))
        		appendUrl = appendUrl.substring(1, appendUrl.length());
        	
            return Uri.parse(serverUrl + appendUrl);
        }
        return fullUri;
    }
    
    /**
     * 获取带请求参数的完整URI地址
     */
    @Override
    public Uri getUriWithQueryString() {
        Uri.Builder uriBuilder = new Uri.Builder();
        Uri uri = getUri();
        uriBuilder.scheme(uri.getScheme()).encodedAuthority(uri.getAuthority()).encodedPath(uri.getPath());
        for (NameValuePair pair :queryStrings){
            uriBuilder.appendQueryParameter(pair.getName(), pair.getValue());
        }
        return uriBuilder.build();
    }
    
    /**
     * 发送HTTP请求
     * @return
     * @throws IOException
     */
    protected HttpURLConnection sendForHttpURLConnection() throws HTTPException {
        HttpURLConnection conn = null;
        
        try {
        	String method = getMethod();
	        String url= getUriWithQueryString().toString();
	        URL urlObj = new URL(url);
	        
	        conn = (HttpURLConnection) urlObj.openConnection();
	        conn.setDoInput(true);
	        conn.setUseCaches(false);
	        conn.setInstanceFollowRedirects(false);
	        conn.setRequestMethod(method);
	        conn.setConnectTimeout(connectTimeout);
	        conn.setReadTimeout(readTimeout);
	        conn.setRequestProperty("Charset", "UTF-8");
	        
	        if (method.equals("POST")) {	        	
				conn.setDoOutput(true);
	        	conn.setRequestProperty("Connection", "Keep-Alive");
	        	conn.setRequestProperty("Content-type", "application/json");
	        }
	
	        //请求头参数
	        if (headers != null) {
	            for (String key : headers.keySet()) {
	                conn.setRequestProperty(key, headers.get(key));
	            }
	        }
	        
	        conn.connect();
	        
	        if (!TextUtils.isEmpty(bodyString)) {
		        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
		        out.write(bodyString.getBytes());
		        out.flush();
		        out.close();
	        }
	        
	        return conn;
        } catch (ConnectTimeoutException e1) {
        	e1.printStackTrace();
        	throw new HTTPException(HTTPException.CONNECT_TIMEOUT, "请求链接超时");
        } catch (SocketTimeoutException e2) {
        	e2.printStackTrace();
        	throw new HTTPException(HTTPException.SOCKET_TIMEOUT, "数据读取超时");
        } catch (IOException e3) {
            e3.printStackTrace();
            throw new HTTPException(HTTPException.REQUEST_FAIL, "请求失败");
        }
    }
    
    /**
	 * 读取HTTP请求返回的值
	 * @param conn 链接对象
	 * @return
	 */
	private String readResult(HttpURLConnection conn) {
		InputStream is = null;
		BufferedReader buffer = null;
		
		try {
			is = conn.getInputStream();
			
			String encode = conn.getContentEncoding();
			if (encode != null && encode.equals("gzip")) {
				is = new GZIPInputStream(is);
			}
			buffer = new BufferedReader(new InputStreamReader(is));
			StringBuilder sb = new StringBuilder();
			String line;
			while ((line=buffer.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if (buffer != null) {
				try {
					buffer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if (conn != null) {
				conn.disconnect();
			}
		}
		
		return "";
	}
    
    
    
    @Override
    public <T> T send(Class<T> entityType) throws HTTPException {
        String result = sendForString();
        return JSONHelper.<T>deserialize(entityType, result);
    }
    
    @Override
	public <T> void sendAsync(final Class<T> entityType, final IHTTPListener<T> listener)
			throws HTTPException {
		sendAsyncForString(new IHTTPListener<String>(){
			@Override
			public void onSuccess(Object req, String result) {
				listener.onSuccess(req, JSONHelper.<T>deserialize(entityType, result));
			}

			@Override
			public void onException(Object req, HTTPException e) {
				listener.onException(req, e);
			}
		});
	}
    
    @Override
    public IResponseInfo send() throws HTTPException {
        IResponseInfo responseInfo;
		try {
			responseInfo = (IResponseInfo) new HttpUrlConnectionResponseInfo(sendForHttpURLConnection());
		} catch (HTTPException e) {
			e.printStackTrace();
			throw e;
		}
        return responseInfo;
    }
    
    @Override
	public void sendAsync(final IHTTPListener<IResponseInfo> listener) {
		 new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					final IResponseInfo responseInfo = (IResponseInfo) new HttpUrlConnectionResponseInfo(sendForHttpURLConnection());
					listener.onSuccess(null, responseInfo);
				} catch (final HTTPException e) {
					e.printStackTrace();
					listener.onException(null, e);
				}
			}
		}).start();		
	}    
    
    @Override
    public <T> List<T> sendForList(Class<T> entityType) throws HTTPException {
        String result = sendForString();
        return JSONHelper.deserializeArray(entityType, result);
    }
    
    @Override
	public <T> void sendAsyncForList(final Class<T> entityType,
			final IHTTPListener<List<T>> listener) throws HTTPException {
		sendAsyncForString(new IHTTPListener<String>() {
			@Override
			public void onSuccess(Object req, String result) {
				listener.onSuccess(req, (List<T>) JSONHelper.deserializeArray(entityType, result));
			}

			@Override
			public void onException(Object req, HTTPException e) {
				listener.onException(req, e);
			}
		});
	}        
    
    @Override
    public String sendForString() throws HTTPException {
        HttpURLConnection conn = null;
        try {
            conn = sendForHttpURLConnection();
            return readResult(conn);
        } catch (HTTPException e) {
        	e.printStackTrace();
        	throw e;
        }
    }

    @Override
	public void sendAsyncForString(final IHTTPListener<String> listener) throws HTTPException {
		new Thread(new Runnable() {			
			@Override
			public void run() {
				Handler handler = new Handler(Looper.getMainLooper());				
					
				try {
					final String result = sendForString();
					
					handler.post(new Runnable() {
						@Override
						public void run() {
							listener.onSuccess(null, result);
						}
					});
				} catch (final HTTPException e) {
					e.printStackTrace();
					handler.post(new Runnable() {
						@Override
						public void run() {
							listener.onException(null, e);
						}
					});
				}
			}
		}).start();
	}


}
